home *** CD-ROM | disk | FTP | other *** search
Text File | 2000-10-30 | 38.2 KB | 1,317 lines |
- ## -*-Tcl-*-
- # # ###################################################################
- # Alpha - new Tcl folder configuration
- #
- # FILE: "tclMode.tcl"
- # created: 5/4/97 {9:31:10 pm}
- # last update: 10/18/00 {11:21:29 am}
- # Author: Vince Darley
- # E-mail: <vince@santafe.edu>
- # mail: 317 Paseo de Peralta
- # Santa Fe, NM 87501, USA
- # www: <http://www.santafe.edu/~vince/>
- #
- # Copyright (c) 1997-2000 Vince Darley
- #
- # Three procs from original: Tcl::DblClick listArray, getVarValue
- #
- # Adds support for Tk, Itcl keywords and completions, plus
- # numerous fixes, improvements and integration with Vince's
- # Additions.
- # ###################################################################
- ##
-
- # Since this is included only for mode demonstration purposes, we make sure
- # that it never gets loaded.
- error "The \"Tcl-Example.tcl\" file should never be loaded !!"
-
- alpha::mode Tcl 1.8.4 tclMenu {*.tcl *.itcl *.itk *.tbc tclIndex*} {
- tclMenu electricTab electricReturn electricBraces alphaDeveloperMenu
- } {
- addMenu tclMenu "•269" "Tcl" "Tcl menu\r\rnot very obvious..."
- set unixMode(wish) {Tcl}
- set unixMode(tclsh) {Tcl}
- set unixMode(itclsh) {Tcl}
- set unixMode(itkwish) {Tcl}
- set unixMode(prowish) {Tcl}
- set unixMode(protclsh) {Tcl}
- ensureset tclshSig "WIsH"
- ensureset evaluateRemotely 0
- trace variable evaluateRemotely w tcltk::evaluateRemoteSynchronise
- menu::buildProc tclMenu menu::buildtclMenu
- lappend tclColourings Tcl::colorTclKeywords \
- Tcl::colorTkKeywords \
- Tcl::colorItclKeywords Tcl::colorPseudoTclKeywords \
- Tcl::colorTkCommands Tcl::colorSymbols
- } maintainer {
- "Vince Darley" vince@santafe.edu <http://www.santafe.edu/~vince/>
- } uninstall this-file help {
- This mode is for editing Tcl code. You can edit code for internal
- use with Alpha, or use Alpha as an external editor for code destined
- for use with Tcl and Tk interpreters --- Sun distributes the Wish
- application and a tcl-tk browser plugin.
-
- You can 'evaluate' a procedure (or any Tcl code for that matter) to
- make changes on the fly. If you select 'Evaluate Remotely' in the
- tcl-tk submenu, then such actions will actually send the code
- to a separately running Wish application to be evaluated.
- }
-
- namespace eval tcltk {}
- proc tclMenu {} {}
-
- # ◊◊◊◊ menu and prefs ◊◊◊◊ #
- # The menu.
- proc menu::buildtclMenu {} {
- global tclMenu evaluateRemotely tcltk::executables
- set execs {}
- if {[info exists tcltk::executables]} {
- lappend execs "\(-"
- foreach ex ${tcltk::executables} {
- lappend execs [file tail $ex]
- }
- }
- set ma [list \
- "/Levaluate" "/-<UswitchToTclsh" \
- [list Menu -n "tcl-tk" -p tcltk::menuProc [concat [list \
- "![lindex {{ } •} $evaluateRemotely]evaluateRemotely" \
- executeCommand executeFileInRemoteShell addWindowToListOfExecutables] \
- $execs]] \
- "\(-" "/L<O<BreloadProc" "/I<O<BreformatProc" \
- "rebuildTclIndexForWin" "\(-" \
- "<U/PfindProcDefinition…" "/Q<IquickFindProc…" "getVarValue…" \
- "/4<BaddRemoveDollars" "/3<BinsertDivider" \
- "\(-" "regularExpressionColors" "defaultColors"]
- return [list build $ma Tcl::MenuProc "" $tclMenu]
- }
- menu::buildSome tclMenu
-
- #===============================================================================
- #
- # Set up package-specific mode variables
- #
-
- # Removing obsolete preferences from earlier versions.
- prefs::removeObsolete TclmodeVars(alphaKeyWordColor) TclmodeVars(keywordColor)
-
- newPref v prefixString {# } Tcl
- newPref f wordWrap {0} Tcl
- newPref v funcExpr {^proc *([+-a-zA-Z0-9]+)} Tcl
- newPref v parseExpr {^proc *([+-a-zA-Z0-9]+)} Tcl
- newPref v wordBreak {(\$)?[\w:_]+} Tcl
- newPref v wordBreakPreface {([^\w:_\$]|.\$)} Tcl
- newPref f autoMark 0 Tcl
- # Indentation scheme for lines following one ending in a backslash
- newPref v indentSlashEndLines 1 Tcl "" indent::amounts varindex
- # Mark files structurally, recognising the special comments
- # entered by 'ctrl-3'
- newPref f structuralMarks 0 Tcl
-
- set Tcl::startPara {^(.*\{)?[ \t]*(#|$)}
- set Tcl::endPara {^(.*\})?[ \t]*(#|$)}
- set Tcl::commentRegexp {^[ \t]*#}
-
- # Not sure if this is used by completions still...
- set Tclcmds { append array catch close concat continue elseif error
- for foreach format lindex llength lrange lreplace lsearch lsort regexp
- regsub rename return string switch while }
-
- #===============================================================================
- #
- # Colorization setup
- #
-
- # Colour Tk commands
- newPref f recogniseTk {1} Tcl {Tcl::updateColors}
- # Colour [incr Tcl] commands
- newPref f recogniseItcl {1} Tcl {Tcl::updateColors}
- # Recognise and colour some common procedures 'lunion' etc.
- newPref f recognisePseudoTcl {1} Tcl {Tcl::updateColors}
- # Colour of all chosen commands.
- newPref v commandColor {blue} Tcl {Tcl::updateColors}
- # Color for Tcl comments
- newPref v commentColor {red} Tcl {Tcl::updateColors}
- # Colour of the $ magic character.
- newPref v magicColor {black} Tcl {Tcl::updateColors}
- # Colour for strings
- newPref v stringColor {green} Tcl {Tcl::updateColors}
- # Colour of symbols such as \, -, +, *, etc. Can be useful for
- # reading regular expressions.
- newPref v symbolColor {black} Tcl {Tcl::updateColors}
-
- ##
- # -------------------------------------------------------------------------
- #
- # "Tcl::_updateKeywords" --
- #
- # This proc now includes support for optional separate colorization of
- # alpha commands. To use, set 'alphaKeyWordColor' to something other than
- # 'none' in the Tcl Mode Preferences dialog. -trf
- # -------------------------------------------------------------------------
- #
- # Now split into a series of procs, called in the end by colorizeTcl. -cbu
- #
- # -------------------------------------------------------------------------
- ##
-
- #===============================================================================
- #
- # Color procs begin here #
- #
-
-
- #===============================================================================
- #
- # Color Tcl Keywords
- #
-
- proc Tcl::colorTclKeywords {} {
- global TclmodeVars
-
- # all except beep and echo are basic Tcl keywords
-
- set tclKeyWords {
- after append array auto_execok auto_import auto_load
- auto_load_index auto_qualify beep binary break case catch cd clock
- close concat continue dde default echo else elseif encoding eof
- error eval exec exit expr fblocked fconfigure fcopy file
- fileevent flush for foreach format gets glob global history if
- incr info interp join lappend lindex linsert list llength load
- lrange lreplace lsearch lsort namespace open package pid
- pkg_mkIndex proc puts pwd read regexp regsub rename resource
- return scan seek set socket source split string subst switch
- tclLog tclMacPkgSearch tclPkgSetup tclPkgUnknown tell time
- trace unknown unset update uplevel upvar variable vwait while
- }
-
- regModeKeywords -a \
- -e {#} -c $TclmodeVars(commentColor) \
- -s $TclmodeVars(stringColor) \
- -k $TclmodeVars(commandColor) Tcl \
- $tclKeyWords
-
- }
-
-
-
-
- #===============================================================================
- #
- # Color Tk Keywords
- #
-
- proc Tcl::colorTkKeywords {} {
- global TclmodeVars
-
- set tkKeyWords {
- bell bind bindtags button canvas checkbutton console destroy
- entry event focus font frame grab grid image label listbox menu
- menubutton message pack place radiobutton raise scale scrollbar
- text tk tkwait toplevel winfo wm
- }
-
- if {$TclmodeVars(recogniseTk)} {
- regModeKeywords -a \
- -k $TclmodeVars(commandColor) Tcl \
- $tkKeyWords
- } else {
- regModeKeywords -a \
- -k {black} Tcl \
- $tkKeyWords
- }
- }
-
-
- #===============================================================================
- #
- # Color iTcl Keywords
- #
-
- proc Tcl::colorItclKeywords {} {
- global TclmodeVars
-
- set itclKeyWords {
- @scope body class code common component configbody constructor
- define destructor hull import inherit itcl itk itk_component
- itk_initialize itk_interior itk_option iwidgets keep method
- private protected public
- }
-
- if {$TclmodeVars(recogniseItcl)} {
- regModeKeywords -a \
- -k $TclmodeVars(commandColor) Tcl \
- $itclKeyWords
- } else {
- regModeKeywords -a \
- -k {black} Tcl \
- $itclKeyWords
- }
- }
-
-
- #===============================================================================
- #
- # Color Pseudo Tcl Keywords
- #
-
- proc Tcl::colorPseudoTclKeywords {} {
- global TclmodeVars
-
- set PseudoTclKeywords {
- lcontains lunion lreverse lremove lunique
- }
- if {$TclmodeVars(recogniseTk)} {
- regModeKeywords -a \
- -k $TclmodeVars(commandColor) Tcl \
- $PseudoTclKeywords
- } else {
- regModeKeywords -a \
- -k {black} Tcl \
- $PseudoTclKeywords
- }
-
- }
-
-
- #===============================================================================
- #
- # Color Tk Commands
- #
- # add this line if we can handle double 'magic chars'
- # -m {tk}
- #
-
- proc Tcl::colorTkCommands {} {
-
- global TclmodeVars
-
- set TkCommands {
- tkButtonDown tkButtonEnter tkButtonInvoke tkButtonLeave tkButtonUp
- tkCancelRepeat tkCheckRadioInvoke tkDarken tkEntryAutoScan
- tkEntryBackspace tkEntryButton1 tkEntryClosestGap tkEntryInsert
- tkEntryKeySelect tkEntryMouseSelect tkEntryNextWord tkEntryPaste
- tkEntryPreviousWord tkEntrySeeInsert tkEntrySetCursor
- tkEntryTranspose tkEventMotifBindings tkFDGetFileTypes tkFirstMenu
- tkFocusGroup_BindIn tkFocusGroup_BindOut tkFocusGroup_Create
- tkFocusGroup_Destroy tkFocusGroup_In tkFocusGroup_Out tkFocusOK
- tkListboxAutoScan tkListboxBeginExtend tkListboxBeginSelect
- tkListboxBeginToggle tkListboxCancel tkListboxDataExtend
- tkListboxExtendUpDown tkListboxMotion tkListboxSelectAll
- tkListboxUpDown tkMbButtonUp tkMbEnter tkMbLeave tkMbMotion
- tkMbPost tkMenuButtonDown tkMenuDownArrow tkMenuDup tkMenuEscape
- tkMenuFind tkMenuFindName tkMenuFirstEntry tkMenuInvoke tkMenuLeave
- tkMenuLeftArrow tkMenuMotion tkMenuNextEntry tkMenuNextMenu
- tkMenuRightArrow tkMenuUnpost tkMenuUpArrow tkMessageBox
- tkPostOverPoint tkRecolorTree tkRestoreOldGrab tkSaveGrabInfo
- tkScaleActivate tkScaleButton2Down tkScaleButtonDown
- tkScaleControlPress tkScaleDrag tkScaleEndDrag tkScaleIncrement
- tkScreenChanged tkScrollButton2Down tkScrollButtonDown
- tkScrollButtonUp tkScrollByPages tkScrollByUnits tkScrollDrag
- tkScrollEndDrag tkScrollSelect tkScrollStartDrag tkScrollToPos
- tkScrollTopBottom tkTabToWindow tkTearOffMenu tkTextAutoScan
- tkTextButton1 tkTextClosestGap tkTextInsert tkTextKeyExtend
- tkTextKeySelect tkTextNextPara tkTextNextPos tkTextNextWord
- tkTextPaste tkTextPrevPara tkTextPrevPos tkTextResetAnchor
- tkTextScrollPages tkTextSelectTo tkTextSetCursor tkTextTranspose
- tkTextUpDownLine tkTraverseToMenu tkTraverseWithinMenu tk_bisque
- tk_chooseColor tk_dialog tk_focusFollowsMouse tk_focusNext
- tk_focusPrev tk_getOpenFile tk_getSaveFile tk_messageBox
- tk_optionMenu tk_popup tk_setPalette tk_textCopy tk_textCut
- tk_textPaste
- }
-
- if {$TclmodeVars(recogniseTk)} {
- regModeKeywords -a \
- -k $TclmodeVars(commandColor) Tcl \
- $TkCommands
- } else {
- regModeKeywords -a \
- -k {black} Tcl \
- $TkCommands
-
- }
- unset TkCommands
- }
-
-
- #===============================================================================
- #
- # Color Symbols and Magic Character
- #
-
- proc Tcl::colorSymbols {} {
-
- global TclmodeVars
-
- regModeKeywords -a \
- -m {$} \
- -k $TclmodeVars(magicColor) Tcl {} \
- -i "+" -i "-" -i "*" -i "_" -i "\\" \
- -I $TclmodeVars(symbolColor)
- }
-
-
- #===============================================================================
- #
- # Colorize Tcl
- #
-
- proc Tcl::colorizeTcl {} {
- global tclColourings
- foreach p $tclColourings {
- $p
- }
- refresh
- }
-
- # This is a "dummy" command, necessary for the above proc so that all of
- # the "regModeKeywords" commands in the called color procs can be "adds"
- # (-a). When the mode is first invoked, this has to occur before the color
- # procs are called.
-
- regModeKeywords -k {none} Tcl {}
-
- # now we finally colorize
-
- Tcl::colorizeTcl
-
-
- #===============================================================================
- #
- # Tcl:: Update Colors --
- #
- # This allows for changes to take effect without a restart.
- #
- # Danger: Don't include this proc in any {mode}Prefs.tcl file !!!
- #
- # This will source the prefs file, and thus put Alpha in an endless loop.
- # Instead, use the Tcl::colorizeTcl proc in the prefs file, so that
- # "Load Prefs File" will update any local variables. - cbu
- #
-
-
- proc Tcl::updateColors {flag} {
-
- global mode PREFS $flag TclmodeVars
-
- # If the mode has a {mode}Prefs.tcl file, we want to load that as
- # well, otherwise any keywords contained therein won't be updated
- # without a manual "Load Prefs File".
-
- if {[file exists [file join ${PREFS} ${mode}Prefs.tcl]]} {
- uplevel #0 [list source [file join ${PREFS} ${mode}Prefs.tcl]]
- }
-
- Tcl::colorizeTcl
- }
-
- #===============================================================================
- #
- # Regular Expression Colors --
- #
- # Changes color scheme of current window to make it easier to read regular
- # expressions. Preferences aren't actually changed. "defaultColors" will
- # restore to the last stored values of the colors. -cbu
- #
-
- proc Tcl::regularExpressionColors {} {
-
- regModeKeywords -a \
- -e {} \
- -m {$} \
- -s {black} \
- -k {magenta} Tcl {} \
- -i "+" -i "-" -i "*" -i "_" -i "\\" \
- -I {red}
-
- refresh
- }
-
- proc Tcl::defaultColors {} {Tcl::colorizeTcl}
-
-
- # ???? end of keyword colorizing ???? #
-
- #===============================================================================
-
-
- proc Tcl::MenuProc {menu item} {
- switch -glob $item {
- "reformatProc" {
- procs::reformatEnclosing [getPos]
- }
- "reloadProc" {
- procs::loadEnclosing [getPos]
- }
- "findProcDefinition" {
- procs::findDefinition
- }
- "quickFindProc" {
- # use the status line
- procs::quickFindDefn
- }
- "switch*" {
- set v "[string tolower [string range $item 8 end]]Sig"
- global $v
- app::launchFore [set $v]
- }
- "addRemoveDollars" {
- togglePrefix \$
- }
- default {
- menu::generalProc Tcl $item 0
- }
- }
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "Tcl::rebuildTclIndexForWin" --
- #
- # If the file is in Alpha's source tree, use the currently loaded
- # auto_mkindex. If it is not, then fire up a separate Tcl application
- # and use its auto_mkindex (i.e. the standard Tcl one). It just occured
- # to me that for Tcl >= 8.0, we could create a new interp, and
- # execute auto_mkindex within that to the same effect, but without
- # the overhead of a whole new process (especially a Tk one!).
- # -------------------------------------------------------------------------
- ##
- proc Tcl::rebuildTclIndexForWin {} {
- if {[alpha::inAlphaHierarchy [win::Current]]} {
- auto_mkindex [file dirname [win::Current]]
- auto_reset
- } else {
- # This will currently launch a Tk shell, which isn't ideal.
- set dir [file dirname [win::Current]]
- tcltk::launchNewShell "auto_mkindex $dir" "exit"
- }
- }
-
- proc tcltk::menuProc {menu item} {
- global tcl_platform tclshSig
- switch -- $item {
- "evaluateRemotely" {
- global evaluateRemotely
- set evaluateRemotely [expr {1 - $evaluateRemotely}]
- }
- "executeFileInRemoteShell" {
- tcltk::executeInRemoteShell [win::Current]
- }
- "addWindowToListOfExecutables" {
- global tcltk::executables
- lappend tcltk::executables [win::Current]
- prefs::modified tcltk::executables
- menu::buildSome tclMenu
- }
- "executeCommand" {
- set cmd [getline "Please enter the script to send to tcl-tk"]
- if {$cmd == ""} {return}
- if {$tcl_platform(platform) == "macintosh"} {
- set res [AEBuild -r -t 30000 '$tclshSig' misc dosc ---- "“$cmd”"]
- } else {
- set res [tcltk::evaluate $cmd]
- }
- alertnote "Result was '$res'"
- }
- default {
- global tcltk::executables
- foreach ex ${tcltk::executables} {
- if {[file tail $ex] == $item} {
- tcltk::executeInRemoteShell $ex
- break
- }
- }
- }
- }
- }
-
- proc tcltk::executeInRemoteShell {f} {
- global evaluateRemotely
- set realName [stripNameCount $f]
- tcltk::launchNewShell \
- "cd [file dirname $realName]" \
- "source [file tail $realName]"
- if {!$evaluateRemotely} {
- set evaluateRemotely 1
- }
- }
-
- proc tcltk::evaluateRemoteSynchronise {args} {
- global evaluateRemotely tclMenu
- catch {markMenuItem "tcl-tk" evaluateRemotely $evaluateRemotely}
- if {$evaluateRemotely} {
- if {[info commands notRemoteEvaluate] == ""} {
- rename evaluate notRemoteEvaluate
- ;proc evaluate {} {remoteEvaluate}
- }
- menu::replaceRebuild tclMenu "•320"
- } else {
- if {[info commands notRemoteEvaluate] != ""} {
- rename evaluate {}
- rename notRemoteEvaluate evaluate
- }
- menu::replaceRebuild tclMenu "•269"
- }
- }
-
-
- proc remoteEvaluate {} {
- message "Remote reply: [tcltk::evaluate [getSelect]]"
- }
-
- proc tcltk::evaluate {what} {
- global tclshSig tcl_platform
- if {$tcl_platform(platform) == "macintosh"} {
- app::ensureRunning $tclshSig
- if {[catch {set r [tclAE::build::resultData -t 30000 '${tclshSig}' \
- misc dosc \
- ---- [tclAE::build::TEXT $what] \
- ]} res]} {
- set res "Error: $res"
- }
- #catch {dosc -c '${tclshSig}' -s $what} res
- #return $res
- } else {
- global tclshInterp
- if {![info exists tclshInterp]} {
- if {[catch {tcltk::findTclshInterp}]} {
- return "No shell selected"
- }
- }
- if {$tcl_platform(platform) == "windows"} {
- if {[dde services TclEval $tclshInterp] == ""} {
- alertnote "The remote shell has died, please select a new one."
- unset tclshInterp
- return [tcltk::evaluate $what]
- }
- dde execute TclEval $tclshInterp [list catch $what alpha_result]
- return [dde request TclEval $tclshInterp alpha_result]
- } else {
- catch {send $tclshInterp $what} res
- }
- }
- return $res
- }
-
- proc tcltk::listInterps {} {
- global tcl_platform
- if {$tcl_platform(platform) == "windows"} {
- set res {}
- foreach service [dde services TclEval ""] {
- lappend res [lindex $service 1]
- }
- return $res
- } else {
- return [winfo interps]
- }
- }
-
- proc tcltk::findTclshInterp {} {
- global tclshInterp tclshSigs tclshSig
- set old [tcltk::listInterps]
- set shel [listpick -p "Use which Tcl shell?" [concat $old \
- [list "------------------" "Launch new shell"]]]
- if {$shel == "Launch new shell"} {
- tcltk::launchNewShell
- } else {
- set tclshInterp $shel
- }
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "tcltk::launchNewShell" --
- #
- # Startup up a new Tcl shell, ensuring that we can communicate with that
- # shell. On Unix/MacOS this should be easy using 'send' or apple-events
- # respectively. On Windows we have to set up the new shell as a dde
- # server. We do this with the script 'winRemoteShell.tcl'.
- #
- # Any extra 'args' passed to this procedure are executed, one by one,
- # in the new shell.
- # -------------------------------------------------------------------------
- ##
- proc tcltk::launchNewShell {args} {
- global tclshInterp tclshSigs tclshSig tcl_platform HOME
- set old [tcltk::listInterps]
- if {$tcl_platform(platform) == "windows"} {
- app::runScript tclsh "Tcl shell" [file join $HOME Tools winRemoteShell.tcl] 1
- } else {
- app::launchElseTryThese $tclshSigs tclshSig "Please locate the remote Tcl application"
- }
- while {[tcltk::listInterps] == $old} {
- update
- }
- set tclshInterp [lremove -l [tcltk::listInterps] $old]
- # We're left with two items
- set tclshInterp [lindex $tclshInterp 0]
-
- if {[llength $args]} {
- foreach arg $args {
- tcltk::evaluate $arg
- }
- }
- }
-
- # ◊◊◊◊ Quick Find Proc… ◊◊◊◊ #
-
- proc procs::quickFindDefn {} {
- Tcl::DblClickHelper [prompt::statusLineComplete "proc" procs::complete]
- }
-
- if {[info tclversion] < 8.0} {
- proc procs::complete {pref} {
- return [info commands ${pref}*]
- }
- } else {
- proc procs::complete {pref} {
- if {[regexp {(.*)([^:]+)$} $pref "" start tail]} {
- set cmds [info commands ${pref}*]
- foreach child [namespace children ::$start] {
- if {[string match "::${tail}*" $child]} {
- foreach cmd [info commands ${start}${child}::*] {
- lappend cmds [string trimleft $cmd :]
- }
- }
- }
- return $cmds
- } else {
- return [info commands ${pref}*]
- }
- }
- }
-
- # ◊◊◊◊ electric behaviour ◊◊◊◊ #
- proc Tcl::electricLeft {} {
- if {[literalChar]} { insertText "\{"; return }
- set pat "\}\[ \t\r\n\]*(else(if)?)\[ \t\r\n\]*\$"
- set p [getPos]
- if { [set res [findPatJustBefore "\}" "$pat" $p word]] == "" } {
- insertText "\{"
- return
- }
- # we have an if/else(if)/else
- switch -- $word {
- "else" {
- replaceText [lindex $res 0] $p "\} $word \{\r"
- bind::IndentLine
- }
- "elseif" {
- replaceText [lindex $res 0] $p "\} $word \{"
- }
- }
- }
-
- proc Tcl::electricRight {} {
- if {[literalChar]} { insertText "\}"; return }
- set p [getPos]
- if { [regexp "\[^ \t\]" [getText [lineStart $p] $p]] } {
- insertText "\}"
- blink [matchIt "\}" [pos::math $p - 1]]
- return
- }
- set start [lineStart $p]
- insertText "\}"
- createTMark tcl_er [getPos]
- backwardChar
- bind::IndentLine
- gotoTMark tcl_er ; removeTMark tcl_er
- bind::CarriageReturn
- blink [matchIt "\}" [pos::math $start - 1]]
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "Tcl::correctIndentation" --
- #
- # Returns the correct indentation for the line containing $pos, if that
- # line were to contain ordinary characters only. It is the
- # responsibility of the calling procedure to ensure that if we are to
- # insert/have a line already, that that information is taken into
- # account, by passing in the argument 'next'
- # -------------------------------------------------------------------------
- ##
- proc Tcl::correctIndentation {pos {next ""}} {
- global indent_amounts indentSlashEndLines
- # preliminaries
- if {[pos::compare [set beg [lineStart $pos]] == [minPos]]} { return 0 }
- # if the current line is a comment, we have to check some
- # special cases
- if {[string index $next 0] == "\#"} {
- set p [prevLineStart $beg]
- if {[catch {set p [search -s -f 0 -r 1 -i 0 -m 0 "^\[ \t\]*\[^ \t\r\n\]" \
- [pos::math $beg - 1]]}]} {
- # check for search bug at beginning of file.
- if {[pos::compare $p == [minPos]]} {
- if {[getText [minPos] [pos::math [minPos] + 2]] == "\#\#"} {
- if {([string range $next 0 1] != "\#\#")} {
- return 1
- } else {
- return 0
- }
- }
- }
- return 0
- }
- set prev [pos::math [lindex $p 1] - 1]
- set p [lindex $p 0]
- if {[lookAt $prev] != "\#" || ($beg == [minPos])} {
- # not a comment, so indent with code
- } else {
- set lwhite [posX $prev]
- # it's a comment
- if {[getText $prev [pos::math $prev + 2]] == "\#\#" && \
- [lookAt [pos::math $prev + 2]] != "\#" \
- && ([string range $next 0 1] != "\#\#")} {
- # it's a comment paragraph
- incr lwhite
- }
- }
- }
- set next [string index $next 0]
- if {![info exists lwhite]} {
- if {![catch {search -s -f 0 -r 1 -i 0 -m 0 "^\[ \t\]*\[^\# \t\r\n\]" [pos::math $beg - 1]} lst]} {
- # Find the last non-comment line and get its leading whitespace
- set lwhite [posX [pos::math [lindex $lst 1] - 1]]
- set pe1 [lookAt [pos::math $beg - 2]]
- set lst [lindex $lst 0]
- set lastC [lookAt [lindex [search -s -f 0 -r 1 -i 0 -m 0 "\[^ \t\r\n\]" [pos::math [nextLineStart $lst] - 1]] 0]]
- if {$next == "\}"} {
- incr lwhite $indent_amounts(-2)
- set pe2 [lookAt [pos::math [prevLineStart $beg] - 2]]
- if {$pe1 == "\\"} {
- incr lwhite $indent_amounts(1)
- } else {
- if {$pe2 == "\\"} {
- incr lwhite $indent_amounts(-1)
- }
- }
- if {$lastC == "\{"} {incr lwhite $indent_amounts(2)}
- } else {
- if {$pe1 == "\\"} {
- if {[lookAt [pos::math [prevLineStart $beg] - 2]] != "\\"} {
- incr lwhite $indent_amounts($indentSlashEndLines)
- }
- } else {
- if {$lastC == "\{"} {incr lwhite $indent_amounts(2)}
- if {[lookAt [pos::math $lst - 2]] == "\\"} {
- incr lwhite $indent_amounts(-$indentSlashEndLines)
- }
- }
- }
- } else {
- # basically failed in all the above, so keep current indentation
- set lwhite [posX [text::firstNonWsLinePos $beg]]
- }
- }
- return [expr {$lwhite > 0 ? $lwhite : 0}]
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "Tcl::indentLine" --
- #
- # Indentation for Tcl mode. Better and faster than the generic procedure
- # -------------------------------------------------------------------------
- ##
- proc Tcl::indentLine {} {
- set beg [lineStart [getPos]]
- set text [getText $beg [nextLineStart $beg]]
- regexp "^\[ \t\]*" $text white
- set next [pos::math $beg + [string length $white]]
- set nextp [pos::math $next + 2]
- if {[pos::compare $nextp > [maxPos]]} {
- set nextp [maxPos]
- }
- set lwhite [Tcl::correctIndentation [getPos] [getText $next $nextp]]
-
- set lwhite [text::indentOf $lwhite]
- if {$white != $lwhite} {
- replaceText $beg $next $lwhite
- }
- goto [pos::math $beg + [string length $lwhite]]
- }
- # ◊◊◊◊ Tcl Menu support ◊◊◊◊ #
-
- proc procs::reformatEnclosing {pos} {
- set p [procs::findEnclosing $pos "proc|((itcl::)?(body|configbody))" 0 1]
- eval select $p
- ::indentRegion
- }
-
- proc procs::loadEnclosing {pos} {
- if {[catch {procs::findEnclosing $pos "proc|((itcl::)?(body|configbody))" 0 1} p]} {
- evaluateLine $pos
- } else {
- eval select $p
- if {[catch {uplevel \#0 evaluate} err]} {
- if {[regexp {can't create procedure "(.*)": unknown namespace} $err "" pr]} {
- if {[dialog::yesno "The procedure '$pr' couldn't be loaded, because\
- it is in an unknown namespace. Shall I create the namespace and\
- try again?"]} {
- ensureNamespaceExists $pr
- return [procs::loadEnclosing $pos]
- }
- }
- }
- }
- goto $pos
- }
-
- proc procs::findDefinition {} {
- if {[llength [winNames]] && [string length [set sel [getSelect]]]} {
- set func [listpick -L $sel -p {Proc?} [lsort -ignore [info procs]]]
- } else {
- set func [listpick -p {Proc?} [lsort -ignore [info procs]]]
- }
-
- editMark [procs::find $func] $func
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "insertDivider" --
- #
- # Modified from Vince's original to allow you to just select part of
- # an already written comment and turn it into a Divider. -trf
- # -------------------------------------------------------------------------
- ##
- proc insertDivider {} {
- if {[isSelection]} {
- set enfoldThis [getSelect]
- beginningOfLine
- killLine
- insertText "# ◊◊◊◊ $enfoldThis ◊◊◊◊ #"
- return
- }
- elec::Insertion "# ◊◊◊◊ •• ◊◊◊◊ #"
- }
-
- # ◊◊◊◊ Info providers ◊◊◊◊ #
- #===============================================================================
-
-
- proc Tcl::DblClick {from to shift option control} {
-
- # if cmd and cntrl were pressed, we look to select part of
- # a combination word (less any leading dollar sign) -trf
- if {$control != 0} {
- set clickedPos [getPos]
- if {[lookAt $from] == "\$"} {
- set from [pos::math $from + 1]
- }
- set sel_start $clickedPos
- set selStartNotDetermined 1
- while {$selStartNotDetermined && ([pos::math $sel_start > $from])} {
- set char [lookAt $sel_start]
- if {[regexp {_} $char]} {
- set sel_start [pos::math $sel_start + 1]
- set selStartNotDetermined 0
- } elseif {[regexp {[A-Z]} $char]} {
- set selStartNotDetermined 0
- } else {
- set sel_start [pos::math $sel_start -1]
- }
- }
- set sel_end $clickedPos
- set selEndNotDetermined 1
- while {$selEndNotDetermined && ([pos::math $sel_end <= $to])} {
- set char [lookAt $sel_end]
- if {[regexp "\[A-Z_ \t\r\]" $char]} {
- set selEndNotDetermined 0
- } else {
- set sel_end [pos::math $sel_end + 1]
- }
- }
- select $sel_start $sel_end
- return
- }
-
- # otherwise, we try to impart some extra info
- select $from $to
-
- if {[catch {Tcl::DblClickHelper [getSelect]}]} {
- message "No docs $shift $control $option"
- }
- }
-
-
- # Now finds commands in Alpha Commands,
- # which has a <cr> immediately after them, e.g. beep, ticks.
- proc Tcl::DblClickHelper {text} {
- global HOME auto_index auto_path
- # Is it a loadable proc?
- if {[string length [set f [procs::find $text]]]} {
- if {[editMark $f $text]} {
- # some marking schemes commonly used for Tcl modes
- goto [lindex [search -s -f 1 -r 1 -m 0 -- "proc\[ \t\]+${text}" [minPos]] 0]
- }
- return
- }
-
- if {[info exists "auto_index($text)"]} {
- if {[editMark "$auto_index($text)" $text]} {
- # some marking schemes commonly used for Tcl modes
- goto [lindex [search -s -f 1 -r 1 -m 0 -- "proc\[ \t\]+${text}" [minPos]] 0]
- }
- return
- }
- # Is it a built-in Alpha command?
- set lines [grep "^• $text\( |\$)" [file join $HOME Help "Alpha Commands"]]
- if {[string length $lines]} {
- if {[catch {editMark [file join $HOME Help "Alpha Commands"] $text}]} {
- # mark failed for some reason, but we have the line number
- # anyway.
- file::openQuietly [file join $HOME Help "Alpha Commands"]
- goto [rowColToPos [string trimright [lindex [lindex [split $lines "\n"] 1] 3] :] 0]
- }
- setWinInfo read-only 1
- return
- }
- # Is it a core Tcl command?
- set lines [grep "^ $text -" [file join $HOME Help "Tcl Commands"]]
- if {[string length $lines]} {
- if {[catch {editMark [file join $HOME Help "Tcl Commands"] $text}]} {
- # mark failed for some reason, but we have the line number
- # anyway.
- file::openQuietly [file join $HOME Help "Tcl Commands"]
- goto [rowColToPos [string trimright [lindex [lindex [split $lines "\n"] 1] 3] :] 0]
- }
- setWinInfo read-only 1
- return
- }
- # Is it a global variable?
- if {[llength [info globals [string trimleft $text {$}]]]==1} {
- showVarValue [string trimleft $text {$}]
- return
- }
- # (becoming desperate) is it a mark in the current file?
- if {[lsearch [getNamedMarks -n] ${text}] != -1} {
- gotoMark $text
- return
- }
- error ""
- }
-
- #############################################################################
- # Report the current value of a global variable, chosen interactively
- # from a list of all active variables.
- #
- # If the variable is an array, or its value is too big to fit in an
- # alertnote, then its contents are listed in a new window, otherwise
- # the variable's value is displayed in an alertnote.
- #
- proc getVarValue {} {
- if {[catch {getText [getPos] [selEnd]} def]} {set def ""}
- set var [getVarFromList $def]
- if {[string length $var] == 0} return
- showVarValue $var
- }
-
- if {[info tclversion] < 8.0} {
-
- proc getVarFromList {{def ""}} {
- return [listpick -p {Which var?} -L $def [lsort -ignore [info globals]]]
- }
-
- } else {
-
- proc getVarFromList {{def ""}} {
- set ns "[namespace qualifiers $def]"
- set def [namespace tail $def]
-
- set items {}
- foreach var [info vars "${ns}::*"] {
- lappend items [namespace tail $var]
- }
- foreach space [namespace children $ns] {
- lappend items "[namespace tail $space]::"
- }
-
- set items [concat "::" [lsort -ignore $items]]
- set var [listpick -p "Which var in namespace ${ns}::?" -L $def $items]
- if {$var == "::"} {
- set var [getVarFromList $ns]
- } elseif {[namespace qualifiers $var] != ""} {
- set var [getVarFromList "${ns}::${var}"]
- } else {
- set var "${ns}::${var}"
- }
- return $var
- }
- }
-
- #############################################################################
- # Report the current value of a global variable, chosen interactively
- # from a list of all active variables.
- #
- # If the variable is an array, or its value is too big to fit in an
- # alertnote, then its contents are listed in a new window, otherwise
- # the variable's value is displayed in an alertnote.
- #
- proc showVarValue {var} {
- global $var
- if {![array exists $var]} {
- viewValue $var [set $var]
- } else {
- new -n "* $var *" -info [listArray $var]
- # if 'shrinkWindow' is loaded, call it to trim the output window.
- catch {shrinkWindow 2}
- }
- }
-
- #############################################################################
- # List the name and value of each element of the array $arrName.
- # (Convenient to use as a shell command.)
- #
- proc listArray {arrName} {
- global $arrName
- if {[array exists $arrName]} {
- set lines {}
- foreach nm [array names $arrName] {
- lappend lines "\"$nm\"\t\{[set ${arrName}($nm)]\}"
- }
- return [join $lines \r]
- } else {
- alertnote "\"$arrName\" doesn't exist in this context"
- }
- }
-
- # ◊◊◊◊ Marking ◊◊◊◊ #
-
- ##
- # -------------------------------------------------------------------------
- #
- # "Tcl::parseFuncs" --
- #
- # This proc is called by the "braces" pop-up. It returns a dynamically
- # created, alphabetical, list of "pseudo-marks".
- #
- # Author: Tom Fetherston
- # -------------------------------------------------------------------------
- ## called by the "{}" button
- proc Tcl::parseFuncs {} {
- global TclmodeVars
- set end [maxPos]
- set pos [minPos]
- set l {}
- set markExpr "^\[ \t\]*(itcl(::|_))?(class|body|proc|method|(config)?body)\[ \t\]"
- set appearanceList {}
- while {![catch {search -s -f 1 -r 1 -m 0 -i 0 "$markExpr" $pos} res]} {
- set start [lindex $res 0]
- set end [nextLineStart $start]
- set t [getText $start $end]
- append t "\}"
- set argLabel {}
- regsub "^itcl(::|_)" [lindex $t 0] "" what
- switch -- [lindex $t 0] {
- "proc" {
- append argLabel [set word [lindex $t 1]]
- #get the list of arguments
- set argsList [lindex $t 2]
- if {[llength $argsList] > 0} {
- append argLabel " \{"
- foreach arg $argsList {
- if {[llength $arg] == 2 } {
- append argLabel "¿"
- } elseif {[set arg] != "args"} {
- append argLabel "•"
- } else {
- append argLabel "…"
- }
- }
- append argLabel "\}"
- }
- }
- default {
- append argLabel [set word [lindex $t 1]]
- }
- }
- if {[info exists cnts($word)]} {
- # This section handles duplicate. i.e., overloaded names
- set cnts($word) [expr {$cnts($word) + 1}]
- set tailOfTag($word) " ($cnts($word) of $cnts($word))"
- # we want the tag to point to its last occurence
- # because in Tcl, that proc will be 'in-force' when the
- # file is loaded.
- set indx($word) [lineStart [pos::math $start - 1]]
- } else {
- #SO do: remember the following
- set cnts($word) 1
- # if this is the only occurence of this proc, remember where it starts
- set indx($word) [lineStart [pos::math $start - 1]]
- }
- #associate name and tag
- set tag($word) $argLabel
-
- #advance pos to where we want to start the next search from
- set pos $end
- }
-
- set rtnRes {}
-
- if {[info exists indx]} {
- foreach hn [lsort -ignore [array names indx]] {
- set next [nextLineStart $indx($hn)]
- set completeTag [set tag($hn)]
- if {[info exists tailOfTag($hn)]} {
- append completeTag [set tailOfTag($hn)]
- }
-
- lappend rtnRes $completeTag $next
- }
- }
- return $rtnRes
- }
-
- # called by the "M" button
- proc Tcl::MarkFile {} {
- global structuralMarks
- set end [maxPos]
- set pos [minPos]
- set l {}
- if {$structuralMarks} {
- set markExpr {^;?[ ]*(itcl(::|_))?(class|namespace eval|proc|method|(config)?body|# ◊◊◊◊)[ ]}
- } else {
- set markExpr {^;?[ ]*(itcl(::|_))?(class|namespace eval|proc|method|(config)?body)[ ]}
- }
- set class ""
- set hasMarkers 0
- while {![catch {search -s -f 1 -r 1 -m 0 -i 0 "$markExpr" $pos} res]} {
- set start [lindex $res 0]
- set end [nextLineStart $start]
- set t [string trim [getText $start $end] ";"]
- append t "\}"
- if {[catch {lindex $t 0}]} {
- # wasn't a well formed list
- set pos $end
- continue
- }
- regsub "^itcl(::|_)" [lindex $t 0] "" what
- switch -glob $what {
- "proc" -
- "configbody" { set text [lindex $t 1] }
- "method" { set text ${class}::[lindex $t 1] }
- "body" {
- regexp {[a-zA-Z_][a-zA-Z_/0-9]*::[a-zA-Z_][a-zA-Z_/0-9]* } \
- "[lindex $t 1] " text
- }
- "namespace" {
- set ns [lindex $t 2]
- if {[regexp {[^a-zA-Z0-9]} $ns]} {
- set pos $end
- continue
- }
- set text "${ns} 111"
- }
- "*class" {
- set class [lindex $t 1]
- set text "${class} 000"
- }
- "#" {
- regexp "# ◊◊◊◊ (.*) ◊◊◊◊" $t all text
- if {[regexp "^( )|( )# ◊◊◊◊ " $t]} {
- set text " •$text"
- } else {
- set text "•$text"
- }
- set hasMarkers 1
- }
- }
- set pos $end
- if {$structuralMarks} {
- lappend asEncountered $text
- set arr inds
- } else {
- if {[string index $t 0] == ";"} {
- set arr iinds
- } else {
- set arr inds
- }
- }
- set ${arr}($text) [lineStart [pos::math $start - 1]]
- }
-
- set already ""
- set class "#"
- foreach arr {inds iinds} {
- if {[info exists $arr]} {
- if {$arr == "iinds"} {
- setNamedMark "-" 0 0 0
- }
- if {$structuralMarks} {
- set order $asEncountered
- } else {
- set order [lsort -ignore [array names $arr]]
- }
- foreach f $order {
- if {[set el [set ${arr}($f)]] != 0} {
- set next [nextLineStart $el]
- } else {
- set next 0
- }
-
- if { [string first "000" $f] != -1 } {
- set ff "Class '[set class [lindex $f 0]]'"
- } elseif { [string first "111" $f] != -1 } {
- set ff "Namespace '[set class [lindex $f 0]]'"
- } elseif { [string first "${class}::" $f] == 0 } {
- set ff [string range $f [string length $class] end]
- } else {
- set ff $f
- }
- while { [lsearch -exact $already $ff] != -1 } {
- set ff "$ff "
- }
- lappend already $ff
- if {$hasMarkers && ![string match "•*" $ff] } {
- set ff " $ff"
- }
- setNamedMark $ff $el $next $next
- }
- }
- }
- }
-
- # ◊◊◊◊ Misc. ◊◊◊◊ #
-
- ##
- # -------------------------------------------------------------------------
- #
- # "bind::tclContinueComment" --
- #
- # exploits a "feature" in the code that makes a new line a comment whenever
- # you are 'inside' a comment. This proc puts a pound sign at the end of the
- # current line, backsteps, and creates a new line. With the pound sign
- # present you are considered to be in a comment, so the bind::CarriageReturn
- # in the proc, and any subsequent bind::CarriageReturn called by a press of
- # the return key will provide another comment line automatically until the
- # pound sign at the end of the line is removed (killLine is handy for this).
- # -------------------------------------------------------------------------
- ##
- proc bind::tclContinueComment {} {
- insertText {#}
- backwardChar
- bind::CarriageReturn
- deleteChar
- }
- Bind '\r' <c> bind::tclContinueComment Tcl
-
- proc evaluateLine { pos } {
- goto $pos
- beginningLineSelect
- endLineSelect
-
- uplevel \#0 evaluate
- }
-
- #◊◊◊◊>
-
- tcltk::evaluateRemoteSynchronise
-
-